from core.globals import auth, scheduler, site
from core.settings import settings
from fastapi import FastAPI
from contextlib import asynccontextmanager
from fastapi_amis_admin_nav.admin import NavPageAdmin
from sqlmodel import SQLModel
from starlette.responses import RedirectResponse
from starlette.requests import Request
from fastapi import Depends
from fastapi_user_auth.auth.models import User
from fastapi.staticfiles import StaticFiles
from fastapi.middleware.cors import CORSMiddleware
from fastapi_amis_admin.admin import HomeAdmin
from fastapi_amis_admin.amis.components import Page
from apps.home.admin import MyHomeAdmin
from apps.audit.admin import AuditLogAdmin


# 创建lifespan上下文管理器
@asynccontextmanager
async def lifespan(app: FastAPI):
    # 启动时执行的代码
    # 添加checkfirst=True参数，避免重复创建已存在的表，解决MySQL行大小限制问题
    await site.db.async_run_sync(
        SQLModel.metadata.create_all, checkfirst=True, is_session=False
    )
    # 创建默认管理员,用户名: admin,密码: admin, 请及时修改密码!!!
    await auth.create_role_user("admin")
    # 创建默认超级管理员,用户名: root,密码: root, 请及时修改密码!!!
    await auth.create_role_user("root")
    # 运行site的startup方法,加载casbin策略等
    await site.router.startup()
    if not auth.enforcer.enforce("u:admin", site.unique_id, "page", "page"):
        await auth.enforcer.add_policy(
            "u:admin", site.unique_id, "page", "page", "allow"
        )
    # 启动定时任务
    # scheduler.start()

    yield

    # 关闭时执行的代码 (如果需要)
    # 这里可以添加清理代码，如关闭数据库连接、停止定时任务等
    # scheduler.shutdown()


# 创建FastAPI实例
app = FastAPI(
    debug=settings.debug,
    lifespan=lifespan,
    docs_url="/docs",
    redoc_url="/redoc",
    openapi_version="3.0.0",
)

# 【重要】CORS中间件必须在所有其他中间件和路由之前添加 这可以确保CORS头在所有响应中都能正确设置
app.add_middleware(
    CORSMiddleware,
    # 关键配置：解决strict-origin-when-cross-origin错误
    # 使用通配符的同时，确保浏览器兼容性
    allow_origins=["*"],  # 允许所有来源
    allow_credentials=True,  # 允许携带凭证
    allow_methods=[
        "GET",
        "POST",
        "PUT",
        "DELETE",
        "OPTIONS",
        "PATCH",
    ],  # 明确列出所有常用方法
    allow_headers=[
        "Origin",
        "Content-Type",
        "Accept",
        "Authorization",
        "X-Requested-With",
        "Access-Control-Request-Method",
        "Access-Control-Request-Headers",
    ],  # 明确列出常用头
    expose_headers=[
        "Content-Length",
        "Content-Type",
        "Authorization",
        "X-Content-Type-Options",
        "X-Frame-Options",
    ],  # 明确列出需要暴露的头
    max_age=86400,  # 预检请求缓存时间（24小时）
)
# 2. 挂载静态目录（URL前缀：/static，对应本地目录：app/static/）
# 等价于 mount 的简化写法
# app.add_static_files("/img", "img")
app.mount(
    path=settings.STATIC_URL,  # 访问URL：http://xxx/static/...
    app=StaticFiles(directory=settings.STATIC_DIR),  # 本地目录
    name="static",  # 别名（可选）
)
# # 3. 不用CDN ,直接使用本地静态文件CSS，JS，离线的CSS等版本不是最新版的。
from patch import patch_offline

patch_offline(app, static_url="/static")

# 取消默认首页
site.unregister_admin(HomeAdmin)
# 注册自定义首页,也可以在模块@site.register_admin注册
site.register_admin(MyHomeAdmin)


# 安装应用demo
from apps import demo, blog, tower

# demo.setup(app)
# 安装应用blog
# blog.setup(app)
tower.setup(app)
# 页面管理
# site.register_admin(NavPageAdmin)
# site.auth
# 添加认证中间件
auth.backend.attach_middleware(app)


# 挂载后台管理系统
site.mount_app(app)


# 注意1: site.mount_app会默认添加site.db的session会话上下文中间件,如果你使用了其他的数据库连接,请自行添加.例如:
# from core.globals import sync_db
# app.add_middleware(sync_db.asgi_middleware) # 注意中间件的注册顺序.

# 注意2: 非请求上下文中,请自行创建session会话,例如:定时任务,测试脚本等.
# from core.globals import async_db
# async with async_db():
#     async_db.async_get(...)
#     async_db.session.get(...)
#     # do something


# 注册首页路由
@app.get("/")
async def index():
    return RedirectResponse(url=site.router_path)


# some test http://127.0.0.1:8000/auth/get_user
# 要求: 用户必须登录
@app.get("/auth/get_user")
@auth.requires()
def get_user(request: Request):
    return request.user


# 验证路由: 用户拥有admin角色
@app.get("/auth/admin_roles")
@auth.requires("admin")
def admin_roles(request: Request):
    return request.user


# 流入方式：路由参数依赖项, 推荐使用此方式
@app.get("/auth/admin_roles_depend_1")
def admin_roles(user: User = Depends(auth.get_current_user)):
    return user  # or request.user


if __name__ == "__main__":
    import uvicorn

    print(
        "少年，我看你骨骼精奇，是万中无一的编程奇才，有个程序员大佬qq群[217840699]你加下吧!维护世界和平就靠你了！"
    )
    uvicorn.run(
        app="main:app",
        host=settings.host,
        port=settings.port,
        reload=True,
    )
